/******************************************************************************
 * echo_server.c                                                               *
 *                                                                             *
 * Description: This file contains the C source code for an echo server.  The  *
 *              server runs on a hard-coded port and simply write back anything*
 *              sent to it by connected clients.  It does not support          *
 *              concurrent clients.                                            *
 *                                                                             *
 * Authors: Athula Balachandran <abalacha@cs.cmu.edu>,                         *
 *          Wolf Richter <wolf@cs.cmu.edu>                                     *
 *                                                                             *
 *******************************************************************************/

#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "parse.h"

#define ECHO_PORT 9999
#define BUF_SIZE 4096
char recvbuf[BUF_SIZE];
char sendbuf[BUF_SIZE];

int close_socket(int sock)
{
    if (close(sock))
    {
        fprintf(stderr, "Failed closing socket.\n");
        return 1;
    }
    return 0;
}
void unimplemented(int client_sock)
{
    char buf[1024];

    /* HTTP method 不被支持*/
    sprintf(buf, "HTTP/1.1 501 Not Implemented\r\n\r\n");
    send(client_sock, buf, strlen(buf), 0);
}

void bad_request(int client_sock)
{
    char buf[1024];

    /*回应客户端错误的 HTTP 请求 */
    sprintf(buf, "HTTP/1.1 400 Bad request\r\n\r\n");
    send(client_sock, buf, strlen(buf), 0);
}
void request_post(int client_sock, int readret)
{
    strcpy(sendbuf, recvbuf);
    send(client_sock, sendbuf, readret, 0);
}

int main(int argc, char *argv[])
{
    int sock, client_sock;
    ssize_t readret;
    socklen_t cli_size;
    struct sockaddr_in addr, cli_addr;

    fprintf(stdout, "----- Echo Server -----\n");

    /* all networked programs must create a socket */
    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "Failed creating socket.\n");
        return EXIT_FAILURE;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(ECHO_PORT);
    addr.sin_addr.s_addr = INADDR_ANY;

    /* servers bind sockets to ports---notify the OS they accept connections */
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
    {
        close_socket(sock);
        fprintf(stderr, "Failed binding socket.\n");
        return EXIT_FAILURE;
    }

    if (listen(sock, 5))
    {
        close_socket(sock);
        fprintf(stderr, "Error listening on socket.\n");
        return EXIT_FAILURE;
    }

    /* finally, loop waiting for input and then write it back */
    while (1)
    {
        cli_size = sizeof(cli_addr);
        if ((client_sock = accept(sock, (struct sockaddr *)&cli_addr,
                                  &cli_size)) == -1)
        {
            close(sock);
            fprintf(stderr, "Error accepting connection.\n");
            return EXIT_FAILURE;
        }

        readret = 0;

        while ((readret = recv(client_sock, recvbuf, BUF_SIZE, 0)) >= 1)
        {
            // 解析HTTP请求
            printf("readret size %ld\n", readret);
            int index;
            Request *request = parse(recvbuf, readret, client_sock);

            if (request)
            {
                printf("Http Method %s\n", request->http_method);
                printf("Http Version %s\n", request->http_version);
                printf("Http Uri %s\n", request->http_uri);
                for (index = 0; index < request->header_count; index++)
                {
                    printf("Request Header\n");
                    printf("Header name %s Header Value %s\n", request->headers[index].header_name, request->headers[index].header_value);
                }
                // 处理 GET 方法
                if (strcasecmp(request->http_method, "GET") == 0)
                {
                    request_post(client_sock, readret);
                }
                // 处理 HEAD 方法
                else if (strcasecmp(request->http_method, "HEAD") == 0)
                {
                    request_post(client_sock, readret);
                }
                // 处理 POST 方法
                else if (strcasecmp(request->http_method, "POST") == 0)
                {
                    request_post(client_sock, readret);
                }
                /*如果不是 GET HEAD POST 则无法处理 返回501*/
                else
                // (strcasecmp(request->http_method, "GET") && strcasecmp(request->http_method, "HEAD") && strcasecmp(request->http_method, "POST"))
                {
                    unimplemented(client_sock);
                }

                // 释放资源
                free(request->headers);
                free(request);
            }
            else
            {
                printf("Request error\n");
                // 错误请求
                bad_request(client_sock);
            }

            memset(sendbuf, 0, BUF_SIZE);
            memset(recvbuf, 0, BUF_SIZE);
        }
        if (readret == -1)
        {
            close_socket(client_sock);
            close_socket(sock);
            printf("Error reading from client socket.\n");
            return EXIT_FAILURE;
        }

        if (close_socket(client_sock))
        {
            close_socket(sock);
            printf("Error closing client socket.\n");
            return EXIT_FAILURE;
        }
    }
    close_socket(sock);

    return EXIT_SUCCESS;
}